/* verilator lint_off UNOPTFLAT */
module decoder(
    input  [ 4:0] op,
    input  [ 7:0] op3,
    input  [ 8:0] op37,
    output [ 4:0] imm_sel,
	output		  src_csr_sel,
    output [ 1:0] src1_sel,
    output [ 2:0] src2_sel,
    output [ 3:0] dst_sel,
    output [10:0] alu_op,

    //branch
    input         branch_rs1_eq_rs2,
    output        branch_beq_bne,
	output		  branch_bge,
	output		  branch_blt,

    //jump
    output        jal,
    output        jalr,

    //store&load
    output [3:0] ls_op,
	
	//ecall
	output		 ecall,

    //ebreak
    input         op_ebreak,//位于instr[20]
    output        ebreak,

    //op_prefix
    input op_prefix
);
//输入选择
wire src1_is_pc,src1_is_rs1;
wire src2_is_imm,src2_is_rs2,src2_is_4;
//输出选择
wire dst_store,dst_load,dst_writeback,dst_writeback_csr;
//指令
wire inst_lui,
     inst_auipc;

wire inst_add,
     inst_addi,
     inst_sub;

//debug:riscv没有nor和nori
wire inst_and,
     inst_andi,
     inst_or,
     inst_ori,
     inst_xor,
     inst_xori;

wire inst_slt,
     inst_slti,
     inst_sltu,
     inst_sltiu;

wire inst_sll,//逻辑左移
     inst_slli,
     inst_srl,//逻辑右移
     inst_srli,
     inst_sra,//算术右移
     inst_srai;

wire inst_jal,
     inst_jalr,
     inst_beq,
     inst_bne,
	 inst_bge,
	 inst_bgeu,
     inst_blt,
	 inst_bltu;

wire inst_lb,
     inst_lbu,
     inst_lh,
     inst_lhu,
     inst_lw,
     inst_sb,
     inst_sh,
     inst_sw;

wire inst_csrrw;
	 //inst_csrrs,
	 //inst_csrrc;

assign inst_lui = op==5'b01101;
assign inst_auipc = op==5'b00101;

assign inst_add = op37==9'b01100_000_0;
assign inst_addi = op3==8'b00100_000;
assign inst_sub = op37==9'b01100_000_1;


assign inst_and = op37==9'b01100_111_0;
assign inst_andi = op3==8'b00100_111;
assign inst_or = op37==9'b01100_110_0;
assign inst_ori = op3==8'b00100_110;
assign inst_xor = op37==9'b01100_100_0;
assign inst_xori = op3==8'b00100_100;

assign inst_slt = op37==9'b01100_010_0;
assign inst_slti = op3==8'b00100_010;
assign inst_sltu = op37==9'b01100_011_0;
assign inst_sltiu = op3==8'b00100_011;

assign inst_sll = op37==9'b01100_001_0;
assign inst_slli = op37==9'b00100_001_0;
assign inst_srl = op37==9'b01100_101_0;
assign inst_srli = op37==9'b00100_101_0;
assign inst_sra = op37==9'b01100_101_1;
assign inst_srai = op37==9'b00100_101_1;

assign inst_jal = op==5'b11011;
assign inst_jalr = op3==8'b11001_000;
assign inst_beq = op3==8'b11000_000;
assign inst_bne = op3==8'b11000_001;
assign inst_bge = op3==8'b11000_101; 
assign inst_bgeu = op3==8'b11000_111;
assign inst_blt = op3==8'b11000_100;
assign inst_bltu = op3==8'b11000_110;

assign inst_lb = op3==8'b00000_000 & op_prefix;//debug:对于可识别码全0的非nop指令，需要&一个op_prefix来区分它与nop
assign inst_lbu = op3==8'b00000_100;
assign inst_lh = op3==8'b00000_001;
assign inst_lhu = op3==8'b00000_101;
assign inst_lw = op3==8'b00000_010;

assign inst_sb = op3==8'b01000_000;
assign inst_sh = op3==8'b01000_001;//debug:~src2_is_4忘记加了
assign inst_sw = op3==8'b01000_010;

assign inst_csrrw = op3==8'b11100_001;
//assign inst_csrrs = op3==8'b11100_010;
//assign inst_csrrc = op3==8'b11100_011;


//src1(not csr)
assign src1_is_pc = inst_auipc | inst_jal | inst_jalr;
assign src1_is_rs1 = ~src1_is_pc & ~src_csr_sel;

//src2(not csr)
assign src2_is_4 = inst_jal | inst_jalr;
assign src2_is_imm = ~src2_is_rs2 & ~src2_is_4 & ~src_csr_sel;
assign src2_is_rs2 = inst_add | inst_sub | inst_sll | inst_slt | inst_sltu | inst_xor | inst_srl | inst_sra | inst_or | inst_and | inst_bge | inst_bgeu | inst_blt | inst_bltu;

//dst
assign dst_store = inst_sb | inst_sh | inst_sw;
assign dst_load = inst_lb | inst_lbu | inst_lh | inst_lhu | inst_lw;
assign dst_writeback = ~dst_store 
					 & ~inst_beq & ~inst_bne 
					 & ~inst_bge & ~inst_bgeu 
					 & ~inst_blt & ~inst_bltu 
					 & ~ecall;//writeback包含load写回rf、直接写回rf和例外写回rf
assign dst_writeback_csr = inst_csrrw; 

//alu_op
assign alu_op[ 0] = inst_add | inst_addi
                  | inst_lb  | inst_lbu | inst_lh | inst_lhu | inst_lw
                  | inst_sb  | inst_sh  | inst_sw
                  | inst_jal | inst_jalr
                  | inst_auipc;//alu add

assign alu_op[ 1] = inst_sub;//alu sub
assign alu_op[ 2] = inst_slt  | inst_slti  | inst_bge  | inst_blt;//alu signed comp
assign alu_op[ 3] = inst_sltu | inst_sltiu | inst_bgeu | inst_bltu;//alu unsigned comp
assign alu_op[ 4] = inst_and  | inst_andi;//alu and
assign alu_op[ 5] = inst_or   | inst_ori;//alu or
assign alu_op[ 6] = inst_xor  | inst_xori;//alu xor
assign alu_op[ 7] = inst_sll  | inst_slli;//alu shift left logically
assign alu_op[ 8] = inst_srl  | inst_srli;//alu shift right logically
assign alu_op[ 9] = inst_sra  | inst_srai;//alu shift right arithmetically
assign alu_op[10] = inst_lui  | inst_csrrw;//alu self(只使用操作数src1，执行内容就是输出其本身)

//imm_sel
assign imm_sel[0] = ~(|imm_sel[4:1]);//I 会出现circular logic(WARN UNOPTFLAT)
assign imm_sel[1] = inst_auipc | inst_lui;//U
assign imm_sel[2] = inst_sb | inst_sh | inst_sw;//S
assign imm_sel[3] = inst_beq | inst_bne | inst_bge | inst_bgeu | inst_blt | inst_bltu;//B
assign imm_sel[4] = inst_jal;//J

//src_sel and dst_sel
assign src_csr_sel = inst_csrrw;
assign src1_sel = {src1_is_pc,src1_is_rs1};
assign src2_sel = {src2_is_4,src2_is_rs2,src2_is_imm};
assign dst_sel = {dst_store,dst_load,dst_writeback,dst_writeback_csr};


//load&store
assign ls_op[2:0] = (inst_sb | inst_lb | inst_lbu) ? 3'b001 :
					(inst_sh | inst_lh | inst_lhu) ? 3'b011 :
					(inst_sw | inst_lw)            ? 3'b111 : 3'b000;

assign ls_op[ 3]  = ~(inst_lbu | inst_lhu);

//branch
assign branch_beq_bne = (
    inst_beq && branch_rs1_eq_rs2
||  inst_bne && !branch_rs1_eq_rs2
);
assign branch_bge = inst_bge | inst_bgeu;
assign branch_blt = inst_blt | inst_bltu;

//jump
assign jal = inst_jal;
assign jalr = inst_jalr;


//e-inst
assign ebreak = op37 == 9'b11100_000_0 && op_ebreak;
assign ecall = op37 == 9'b11100_000_0 && ~op_ebreak;

endmodule
